﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Audit.Mapping;
using NHibernate.Cfg;
using NHibernate.Mapping;

namespace NHibernate.Audit.Mapping
{
    public class TableMapper : ITableMapper 
    {

        public virtual Table BuildAuditTable(AuditTableMetadata tableMetadata, ITableFactory tableFactory)
        {
            var realClass = tableMetadata.ClassMetadata.RealClass;
            var auditTable = CreateTable(tableMetadata, tableFactory, realClass);

            CopyIdColumns(auditTable, realClass);
            CopyPropertyColumns(auditTable, tableMetadata);
            CopyRevisionColumn(auditTable, tableMetadata);
            return auditTable;
        }

        protected virtual Table CreateTable(AuditTableMetadata tableMetadata, ITableFactory tableFactory, PersistentClass realClass)
        {
            return tableFactory.CreateTable(tableMetadata.Schema,
                tableMetadata.Catalog, tableMetadata.Name,
                realClass.IsAbstract.GetValueOrDefault());
        }

        protected virtual void CopyIdColumns(Table auditTable, PersistentClass realClass)
        {
            //Always copy the Id columns
            var IdColumns = realClass.IdentifierProperty.ColumnIterator.Cast<Column>();
            foreach (var column in IdColumns)
                auditTable.AddColumn((Column)column.Clone());
        }

        protected virtual void CopyPropertyColumns(Table auditTable, AuditTableMetadata tableMetadata)
        {
            var properties = (from propMeta in tableMetadata.ClassMetadata.Properties
                         select propMeta.Property);

            foreach (var property in properties)
                CopyPropertyColumns(auditTable, property);
        }

        protected virtual void CopyPropertyColumns(Table auditTable, Property property)
        {
            foreach (var column in property.ColumnIterator.Cast<Column>())
                auditTable.AddColumn((Column)column.Clone());
        }

        protected virtual void CopyRevisionColumn(Table auditTable, AuditTableMetadata tableMetadata)
        {
            auditTable.AddColumn(tableMetadata.RevisionColumn);
        }

    }
}
